/*
 * @Author: liaoxin
 * @email: 2858765077@qq.com
 * @FilePath: \personnelmanage\src\lib\pages\BaseListPage\BaseListPage.tsx
 * @Date: 2022-08-29 14:05:03
 * @LastEditTime: 2022-10-12 18:16:53
 */
import _ from 'lodash'
import React, { ReactNode } from 'react'
import BasePage from '../BasePage'
import { UdPageHeader, UdFilter, UdToolbar, UdTable, routeUtils } from '../..'
import { WrappedFormUtils } from 'antd/lib/form/Form'
import ButtonGroup from 'antd/lib/button/button-group'
import { IBaseListPageProps, IBaseListPageState, IListQueryParams, IListRes, IUdFormItem } from '../../types'
import { http } from '../../core/http'
import { AxiosResponse } from 'axios'
import { PaginationConfig } from 'antd/lib/table'
import UdPage from '../../ui/UdPage'
import { formUtils } from '../../utils/formUtils'
import { udConfigProvider } from '../../core/udConfigProvider'
import { Affix, BackTop } from 'antd'

/**
 * 通用基础列表页基类
 */
class BaseListPage<
  P extends IBaseListPageProps = IBaseListPageProps,
  S extends IBaseListPageState = IBaseListPageState,
  QP extends IListQueryParams = IListQueryParams>
  extends BasePage<P, S, QP> {

  static resFieldKeys: {
    content: string,
    number: string
    numberOfElements: string
    size: string
    totalElements: string
    totalPages: string
  } = {
      content: 'content',
      number: 'number',
      numberOfElements: 'numberOfElements',
      size: 'size',
      totalElements: 'totalElements',
      totalPages: 'totalPages'
    }

  static defaultState: IBaseListPageState = {
    title: '',
    method: 'POST',
    queryApi: '',
    rowKey: 'id',
    columns: [],
    pagination: {
      showTotal: (total: number, range: [number, number]) => `共 ${total} 项, 当前 ${range[0]}-${range[1]}`,
      showQuickJumper: true,
      showSizeChanger: true,
      pageSizeOptions: ['10', '20', '40', '60', '100', '150', '200'],
    },
    queryAfterMount: true,
    dataSource: [],
    tableProps: {},
    showColumns: [],
    selectedRowKeys: [],
    selectedRows: [],
    useColumnCustomize: false,
  }

  /** 默认查询参数 */
  protected defaultQueryParams: QP = {
    page: 1,
    size: 10,
    conditions: {},
    v: 0
  } as any


  /** 将请求参数保存到url地址上，并支持浏览器前进后退。 */
  protected saveParamsWithUrl: boolean = true

  /** 条件过滤器的表单对象 */
  protected filterForm: WrappedFormUtils = {} as WrappedFormUtils

  /** 滚动条容器 */
  protected pageContainer = udConfigProvider.ui.getPageContainer()

  /** 通过组件内部设置覆盖全局的配置的把条件放到 conditions 字段中 */
  protected useConditionsField

  componentWillMount(otherState?: Partial<S>) {
    super.componentWillMount()
    let state: IBaseListPageState = _.defaultsDeep({}, {
      pagination: {
        current: this.queryParams.page,
        pageSize: this.queryParams.size
      }
    }, this.state, otherState, BaseListPage.defaultState)

    if (state.leftBtns && state.leftBtns.length > 0) {
      state.tableProps = _.defaultsDeep({}, state.tableProps, {
        rowSelection: {
          onChange: (selectedRowKeys, selectedRows) => {
            let tableProps = this.state.tableProps;
            if (tableProps && tableProps.rowSelection) {
              tableProps.rowSelection.selectedRowKeys = selectedRowKeys
            }
            this.setState({ selectedRowKeys, selectedRows, tableProps })
          }
        }
      })
    }
    // if (state.useColumnCustomize) {
    //   state.rightBtns = state.rightBtns || []
    //   state.rightBtns.push(() => {
    //     return <UdTableColumnCustomize values={this.state.showColumns} columns={state.columns} onChange={this.onTableColumnChange} />
    //   })
    // }
    this.setState(state)
  }

  componentDidMount() {
    // if (this.queryParams.v == 0) {
    //   let initialValues = this.getConditionsInitialValues()
    //   if (_.isEqual(this.defaultQueryParams.conditions, this.queryParams.conditions)) {
    //     this.queryParams.conditions = _.merge({}, this.defaultQueryParams.conditions, initialValues)
    //   }
    // }
    this.queryParamsChanged(true)
  }

  render(slot?: {
    header?: ReactNode
    filterExtraInfo?: ReactNode
    filterBelow?: ReactNode
    footer?: ReactNode
    columns?: any[]
    dataSource?: any[]
  }) {
    const { conditions, leftBtns, rightBtns, useColumnCustomize } = this.state
    const showToolbar = (leftBtns && leftBtns.length > 0) || (rightBtns && rightBtns.length > 0)
    let sortValues = []
    if (this.queryParams.conditions['orderBy']) {
      sortValues.push({ key: this.queryParams.conditions['orderBy'], value: this.queryParams.conditions['orderType'] })
    }
    return (
      <UdPage className="list-page">
        {
          this.state.title && <UdPageHeader title={this.state.title} subTitle={this.state.subTitle}
            onBack={this.state.onBack}
            affixProps={{ target: () => this.pageContainer }} />
        }
        {slot && slot.header}
        {
          (_.isArray(conditions) && conditions.length > 0) && (
            <UdFilter
              loading={this.state.querying} items={conditions}
              getForm={(form) => { this.filterForm = form }}
              onSearch={this.handleSearch} resetAfter={this.filterReset}
              extraInfo={slot && slot.filterExtraInfo}
            ></UdFilter>
          )
        }
        {slot && slot.filterBelow}
        {
          showToolbar && (
            <Affix className="ud-page-toolbar-affix" offsetTop={40} target={() => this.pageContainer}>
              <UdToolbar other={
                <ButtonGroup>
                  {this.buildToolbarBtns(leftBtns)}
                </ButtonGroup>
              }>
                <ButtonGroup>
                  {this.buildToolbarBtns(rightBtns)}
                </ButtonGroup>
              </UdToolbar>
            </Affix>
          )
        }
        {
          useColumnCustomize ?
            <UdTable loading={this.state.querying} rowKey={this.state.rowKey}
              bordered={true}
              sortValues={sortValues}
              pagination={this.state.pagination} {...this.state.tableProps}
              columns={slot.columns} dataSource={slot.dataSource}
              onChange={this.handleTableChange}
            />
            :
            <UdTable loading={this.state.querying} rowKey={this.state.rowKey}
              sortValues={sortValues}
              pagination={this.state.pagination} {...this.state.tableProps}
              columns={this.state.columns} dataSource={this.state.dataSource}
              onChange={this.handleTableChange}
            />
        }
        {slot && slot.footer}
        {this.pageContainer && <BackTop target={() => this.pageContainer} visibilityHeight={100} />}
      </UdPage>
    );
  }

  /**
   * url参数发生改变时
   */
  protected queryParamsChanged = (init?: boolean) => {
    if (init == true || this.saveParamsWithUrl) {
      if (this.queryParams.v == 0) {
        let initialValues = this.getConditionsInitialValues()
        if (_.isEqual(this.defaultQueryParams.conditions, this.queryParams.conditions)) {
          this.queryParams.conditions = _.merge({}, this.defaultQueryParams.conditions, initialValues)
        }
      }
      if (init) {
        if (this.state.queryAfterMount) {
          this.query()
        }
      } else {
        this.query()
      }
      if (this.filterForm && _.isFunction(this.filterForm.setFieldsValue)) {
        formUtils.setValues(this.filterForm, this.state.conditions, this.queryParams.conditions)
      }
    }
  }

  /**
   * 查询
   */
  protected query = () => {
    this.setState({ querying: true })
    let tableProps = this.state.tableProps
    if (tableProps && tableProps.rowSelection && this.state.selectedRowKeys && this.state.selectedRowKeys.length > 0) {
      tableProps.rowSelection.selectedRowKeys = []
      this.setState({ tableProps, selectedRows: [], selectedRowKeys: [] })
    }
    let promise: Promise<AxiosResponse<IListRes>>
    if (_.isFunction(this.state.queryApi)) {
      promise = this.state.queryApi(this.getQueryParams())
    } else {
      if (this.state.method == 'GET') {
        promise = http.get<IListRes>(this.state.queryApi as string, {
          params: this.getQueryParams()
        })
      } else {
        promise = http.post<IListRes>(this.state.queryApi as string, this.getQueryParams())
      }
    }
    promise.then(res => {
      let pagination = this.state.pagination as PaginationConfig | false
      if (pagination) {
        pagination.current = res.data[BaseListPage.resFieldKeys.number]
        pagination.pageSize = res.data[BaseListPage.resFieldKeys.size]
        pagination.total = res.data[BaseListPage.resFieldKeys.totalElements]
      }
      let data = this.handleDataSource(res.data)
      if (pagination && pagination.current > 1 && (data == null || data.length == 0)) {
        this.handleParamsChange({ page: pagination.current - 1 })
      } else {
        data.map(resp => { if (resp.id === null || resp.id === undefined || resp.id === "") resp.id = this.uuid() })
        this.setState({ dataSource: data, pagination })
      }
    }, res => {
      let pagination = this.state.pagination as PaginationConfig | false
      if (pagination) {
        pagination.total = 0
      }
      this.setState({ dataSource: [], pagination })
    }).finally(() => {
      this.setState({ querying: false })
    })
  }

  /**
   * 
   * @returns 生成唯一id
   */
  protected uuid = () => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      var r = Math.random() * 16 | 0,
        v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }

  /**
   * 处理接口返回的数据
   */
  protected handleDataSource = (data: any) => {
    return data[BaseListPage.resFieldKeys.content] || data
  }

  /**
   * 参数发生改变时
   */
  protected handleParamsChange<T = any>(params?: any, merge: boolean = true) {

    let query = this.queryParams
    if (params) {
      if (merge) {
        query = _.extend({}, this.queryParams, params)
      } else {
        query = params as QP
      }
    }
    if (this.saveParamsWithUrl) { // 判断是否需要将参数写到url地址中
      let defaultUrlSearch = routeUtils.searchStringToObject(this.props.history.location.search, this.defaultQueryParams)
      let copyQuery = _.cloneDeep(query)
      delete copyQuery.v
      delete defaultUrlSearch.v
      let isSame = _.isEqual(copyQuery, defaultUrlSearch)
      if (!isSame) {
        this.pushQueryParams(query, false)
      } else {
        this.queryParams = query
        this.query()
      }
    } else {
      this.queryParams = query
      this.query()
    }
  }

  /** 
   * 处理条件过滤器查询事件
   */
  protected handleSearch = (values: any) => {
    let p: Partial<IListQueryParams> = {
      conditions: values,
      v: new Date().getTime()
    }
    if (this.state.pagination) {
      p.page = 1
    }
    this.handleParamsChange<IListQueryParams>(p)
  }

  /**
   * 检索条件重置时
   */
  protected filterReset = (form: WrappedFormUtils) => {
    let defaultValues: any = {}
    _.forEach(this.state.conditions, (item: IUdFormItem) => {
      if (item.initialValue) {
        let key = _.isArray(item.id) ? item.id.join('|') : item.id
        defaultValues[key] = item.initialValue
      }
    })
    var conditions = _.merge({}, this.defaultQueryParams.conditions, defaultValues)
    this.handleSearch(conditions)
  }

  /**
   * 获取查询参数
   * 如果查询参数非常特别可重写此方法
   */
  protected getQueryParams = () => {
    if (this.state.pagination) {
      let req: any = {
        size: this.queryParams.size,
        page: this.queryParams.page
      }
      if (this.useConditionsField !== undefined ? this.useConditionsField : udConfigProvider.api.useConditionsField) {
        req.conditions = {
          ...this.queryParams.conditions
        }
      } else {
        req = { ...req, ...this.queryParams.conditions }
      }
      return req
    } else {
      return this.queryParams.conditions
    }
  }

  /**
   * 列表检索条件发生改变时
   */
  protected handleTableChange = (pagination, filters, sorter, extra) => {
    let baseConditions = this.queryParams.conditions;
    baseConditions.orderType = sorter.order
    baseConditions.orderBy = sorter.field
    let p: Partial<IListQueryParams> = {
      conditions: baseConditions,
      v: new Date().getTime()
    }
    if (this.state.pagination) {
      p.page = pagination.current
      p.size = pagination.pageSize
    }
    this.handleParamsChange<IListQueryParams>(p)
  }

  /**
   * 
   */
  protected onTableColumnChange = (values: string[]) => {
    this.setState({ showColumns: values })
  }

  /**
   * 是否有选中的行
   */
  protected existSelectedRow = () => {
    return this.state && this.state.selectedRowKeys && this.state.selectedRowKeys.length > 0
  }

  /**
   * 构造工具栏的按钮
   */
  protected buildToolbarBtns = (btns?: (ReactNode | (() => ReactNode))[]) => {
    if (Array.isArray(btns) && btns.length > 0) {
      let nodes = []
      for (const btn of btns) {
        let Btn: any = _.isFunction(btn) ? btn() : btn
        if (Btn) {
          nodes.push(React.cloneElement(Btn, { key: _.uniqueId('toolbar_btn_') }))
        }
      }
      return nodes
    }
    return null
  }

  /**
   * 获取条件过滤表单的初始值
   */
  protected getConditionsInitialValues = () => {
    let initialValues: any = {}
    _.forEach(this.state.conditions, (item: IUdFormItem) => {
      if (item.initialValue) {
        let key = _.isArray(item.id) ? item.id.join('|') : item.id
        initialValues[key] = item.initialValue
      }
    })
    return initialValues
  }

}

export default BaseListPage
